package com.lz;

import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;

import static java.lang.System.out;

/**
 * @description
 *
 * 批量重偏向：当一个线程创建了大量对象并执行了初始的同步操作，后来另一个线程也来将这些对象作为锁对象进行操作，会导偏向锁重偏向的操作。
 * 批量撤销：在多线程竞争剧烈的情况下，使用偏向锁将会降低效率，于是乎产生了批量撤销机制。
 *
 *
 * @date 2021-11-09 17:09
 *
 * @author Lizhong
 */
public class ClazzLayout {
    public static void main(String[] args) throws Exception {
        rebiase();
        // noneLock();
        // revoke();
    }

    public static void revoke() throws Exception {


        out.println("新实例A");
        out.println((ClassLayout.parseInstance(new A()).toPrintable()));

        Thread.sleep(5000);
        List<A> listA = new ArrayList<>();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                A a = new A();
                synchronized (a) {
                    listA.add(a);
                }
            }
            try {
                Thread.sleep(100000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        Thread.sleep(3000);

        Thread t2 = new Thread(() -> {
            //这里循环了40次。达到了批量撤销的阈值
            for (int i = 0; i < 40; i++) {
                A a = listA.get(i);
                synchronized (a) {
                }
            }
            try {
                Thread.sleep(10000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t2.start();

        //———————————分割线，前面代码不再赘述——————————————————————————————————————————
        Thread.sleep(3000);
        out.println("打印list中第11个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(10)).toPrintable()));
        out.println("打印list中第26个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(25)).toPrintable()));
        out.println("打印list中第90个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(89)).toPrintable()));


        Thread t3 = new Thread(() -> {
            for (int i = 20; i < 40; i++) {
                A a = listA.get(i);
                synchronized (a) {
                    if (i == 20 || i == 22) {
                        out.println("thread3 第" + i + "次");
                        out.println((ClassLayout.parseInstance(a).toPrintable()));
                    }
                }
            }
        });
        t3.start();


        Thread.sleep(10000);
        out.println("重新输出新实例A");
        A instance = new A();
        out.println((ClassLayout.parseInstance(instance).toPrintable()));
        new Thread(() -> {
            synchronized (instance) {
            }
            out.println("撤销重偏向后");
            out.println((ClassLayout.parseInstance(instance).toPrintable()));


        }).start();
        Thread.sleep(10000);


    }

    private static void rebiase() throws InterruptedException {
        //延时产生可偏向对象
        Thread.sleep(5000);

        //创造100个偏向线程t1的偏向锁
        List<A> listA = new ArrayList<>();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                A a = new A();
                synchronized (a) {
                    listA.add(a);
                }
            }
            try {
                //为了防止JVM线程复用，在创建完对象后，保持线程t1状态为存活
                Thread.sleep(100000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();

        //睡眠3s钟保证线程t1创建对象完成
        Thread.sleep(3000);
        out.println("打印t1线程，list中第20个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(19)).toPrintable()));

        //创建线程t2竞争线程t1中已经退出同步块的锁
        Thread t2 = new Thread(() -> {
            //这里面只循环了30次！！！
            for (int i = 0; i < 30; i++) {
                A a = listA.get(i);
                if (i == 0) {
                    out.println("第" + (i + 1) + "锁状态");
                    out.println((ClassLayout.parseInstance(a).toPrintable()));

                }

                synchronized (a) {
                    //分别打印第19次和第20次偏向锁重偏向结果
                    if (i == 18 || i == 19) {
                        out.println("第" + (i + 1) + "次偏向结果");
                        out.println((ClassLayout.parseInstance(a).toPrintable()));
                    }
                }
            }
            try {
                Thread.sleep(10000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t2.start();

        Thread.sleep(3000);
        out.println("打印list中第11个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(10)).toPrintable()));
        out.println("打印list中第26个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(25)).toPrintable()));
        out.println("打印list中第41个对象的对象头：");
        out.println((ClassLayout.parseInstance(listA.get(40)).toPrintable()));
    }

    public static void noneLock() {
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
        //  操作系统大端模式
        //  CPU小端模式
        // 每8位反向拼接
        A a = new A();
        out.println(Integer.toHexString(a.hashCode()));
        out.println(ClassLayout.parseInstance(a).toPrintable());
        synchronized (a) {
            out.println(Long.toHexString(Thread.currentThread().getId()));
            out.println(ClassLayout.parseInstance(a).toPrintable());
        }
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }

    public void ss() {

        A a = new A();
        // 偏向锁的作用 不需要等到SafePoint时直接尝试重新偏向
        // 轻量级锁 安全点自旋root
        // 重量级锁 操作系统 Queue 抢占式，Cpu yield
        // System.out.println(Integer.toHexString( a.hashCode())); //
        // 默认开启。JDK15关闭偏向锁
        //      在没有计算 System.IdentityHash 时默认匿名偏向 101
        //      在有计算过HashCode 默认无锁状态
        //      下次竞争直接 轻量级锁
        //
        // ObjectSynchronizer::FastHashCode计算HashCode 检测对象
        // r当一个对象已经计算过identity hash code，它就无法进入偏向锁状态；
        // 当一个对象当前正处于偏向锁状态，并且需要计算其identity hash code的话，则它的偏向锁会被撤销，并且锁会膨胀为重量锁；
        // 重量锁的实现中，ObjectMonitor类里有字段可以记录非加锁状态下的mark word，其中可以存储identity hash code的值。
        // 或者简单说就是重量锁可以存下identity hash code。


        System.out.println("A0 : " + Thread.currentThread().getId() + "\n " + ClassLayout.parseInstance(a).toPrintable());
        // synchronized (a) {
        //     System.out.println("A-1: " + +Thread.currentThread().getId() + "\n " + ClassLayout.parseInstance(a).toPrintable());
        //     // a.hashCode();
        //     // try {
        //     //     Thread.sleep(100);
        //     // } catch (InterruptedException e) {
        //     //     e.printStackTrace();
        //     // }
        // }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread thread = new Thread(() -> {
            synchronized (a) {
                //
                System.out.println("A1: " + +Thread.currentThread().getId() + "\n " + ClassLayout.parseInstance(a).toPrintable());
                a.hashCode();
                System.out.println("A1: " + +Thread.currentThread().getId() + "\n " + ClassLayout.parseInstance(a).toPrintable());

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread.start();
        Thread thread1 = new Thread(() -> {
            synchronized (a) {
                System.out.println("A2 : " + Thread.currentThread().getId() + "\n " + ClassLayout.parseInstance(a).toPrintable());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 保证偏向锁无竞争
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("A1-2 : " + Thread.currentThread().getId() + "\n " + ClassLayout.parseInstance(a).toPrintable());

        thread1.start();

        try {
            Thread.sleep(30000);
            System.out.println("A3" + ClassLayout.parseInstance(a).toPrintable());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class A {
}
